/*******************************************************************************
* file  : aes demo
* creat : apleilx
* data  : 2017/03/02
* @brief  	aes 是一种对称加密算法，加密解密主KEY相同
*			该算法以128bit/192bit/256bit为单元进行加密解密，密文和明文尺寸相同
*			本测试代码为128bit模式加密、解密验证
*			16字节KEY，16字节明文，16字节密文
*			堆栈：2KB
*******************************************************************************/
#include "bsp.h"
#include "apm32f4xx_cryp.h"
#include "framework.h"
#include "mbedtls/aes.h"
#include "bsp_api.h"
#include "sys_init.h"

// 此数组为 key_code_sim 代码二进制值
// 作为固定键值，可以伪装为程序
const uint16_t ase_key_src[] = {
	0xf04f, 0x5000, 0x6801, 0x07ca,
	0xd500, 0xbf00, 0x6841, 0x078a,
	0xd500, 0xbf00, 0x6881, 0x074a,
	0xd500, 0xbf00, 0x68c0, 0x0701,
	0xd500, 0xbf00, 0x4770};

#define dat_buff_init()            \
	loop(1000) src[index] = index; \
	memset(enc, 0, 1000);          \
	memset(dec, 0, 1000);

/*******************************************************************************
* @brief  des_demo.
* \param[in] none
* \retval: none
*******************************************************************************/
void aes_cbc_demo(void)
{
	uu32 clk_start;
	uu8 *src, *enc, *dec, *iv;
	mbedtls_aes_context *aes_enc, *aes_dec;
	size_t offset;

	/* Enable CRYP clock */
    RCM_EnableAHB2PeriphClock(RCM_AHB2_PERIPH_CRYP);
	
	// 内存请求
	src = calloc(1, 1024);
	enc = calloc(1, 1024);
	dec = calloc(1, 1024);
	iv = calloc(1, 80);
	aes_enc = malloc(sizeof(mbedtls_aes_context));
	aes_dec = malloc(sizeof(mbedtls_aes_context));
	
	// 初始化
	dbg_puts(SYMBOL_LINE_EQ PTCR);
	dbg_print("AES 128 encode mbedtls: <128 bits> \n");

	/*------------------------------------------------------------------------*/
	// 加密 + 解密 	CBC			密码分组连接模式	- 内部分组 IO长度相同
	// 加密解密需要相同的初始向量, 向量长度16B
	dat_buff_init();
	memset(iv, 0xFF, 16);
	
	clk_start = bsp_cpu_clks_get();
	mbedtls_aes_init(aes_enc);
	mbedtls_aes_setkey_enc(aes_enc, (void *)ase_key_src, 128);
	mbedtls_aes_crypt_cbc(aes_enc, MBEDTLS_AES_ENCRYPT, 256, iv, src, enc);
	dbg_print("mbedtls AES CBC 256 : enc time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	
	memset(iv, 0xFF, 16);
	clk_start = bsp_cpu_clks_get();
	mbedtls_aes_init(aes_dec);
	mbedtls_aes_setkey_dec(aes_dec, (void *)ase_key_src, 128);
	mbedtls_aes_crypt_cbc(aes_dec, MBEDTLS_AES_DECRYPT, 256, iv, enc, dec);
	dbg_print("mbedtls AES CBC 256 : dec time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	// 显示
	dbg_u8_print("enc: \n", enc, 256, 32);
	dbg_u8_print("dec: \n", dec, 256, 32);


	// APM32 CBC
	dbg_puts(SYMBOL_LINE_ADD PTCR);
	dat_buff_init();
	
	memset(iv, 0xFF, 16);
	clk_start = bsp_cpu_clks_get();
    CRYP_Reset();
    CRYP_AES_CBC(CRYP_MODE_ENCRYPT, (uu8*)ase_key_src, 128, iv, src, 256, enc);
	dbg_print("APM32 AES CBC 256 : enc time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	memset(iv, 0xFF, 16);
	clk_start = bsp_cpu_clks_get();
    CRYP_Reset();
    CRYP_AES_CBC(CRYP_MODE_DECRYPT, (uu8*)ase_key_src, 128, iv, enc, 256, dec);
	dbg_print("APM32 AES CBC 256 : dec time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));

	// 显示
	dbg_u8_print("enc: \n", enc, 256, 32);
	dbg_u8_print("dec: \n", dec, 256, 32);
	
	// 释放，用于清除内存中的密匙，属于安全性代码
	mbedtls_aes_free(aes_enc);
	mbedtls_aes_free(aes_dec);

	// 释放内存
	free(src);
	free(enc);
	free(dec);
	free(iv);
	free(aes_enc);
	free(aes_dec);
}

/*******************************************************************************
* @brief  des_demo.
* \param[in] none
* \retval: none
*******************************************************************************/
void aes_ecb_demo(void)
{
	uu32 clk_start;
	uu8 *src, *enc, *dec;
	mbedtls_aes_context *aes_enc, *aes_dec;
	size_t offset;

	/* Enable CRYP clock */
    RCM_EnableAHB2PeriphClock(RCM_AHB2_PERIPH_CRYP);
	
	// 内存请求
	src = calloc(1, 1024);
	enc = calloc(1, 1024);
	dec = calloc(1, 1024);
	aes_enc = malloc(sizeof(mbedtls_aes_context));
	aes_dec = malloc(sizeof(mbedtls_aes_context));
	
	// 初始化
	dat_buff_init();
	
	dbg_puts(SYMBOL_LINE_EQ PTCR);
	dbg_print("AES 128 encode: <128 bits> \n");
	dbg_puts(SYMBOL_LINE_DOT PTCR);

	/*------------------------------------------------------------------------*/
	// 加密 + 解密 	ECB			电子密码本模式
	clk_start = bsp_cpu_clks_get();
	mbedtls_aes_init(aes_enc);
	mbedtls_aes_setkey_enc(aes_enc, (void *)ase_key_src, 128);
	loop(16)
	mbedtls_aes_crypt_ecb(aes_enc, MBEDTLS_AES_ENCRYPT, src+index*16, enc+index*16);
	dbg_print("mbedtls AES ECB encode time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	clk_start = bsp_cpu_clks_get();
	mbedtls_aes_init(aes_dec);
	mbedtls_aes_setkey_dec(aes_dec, (void *)ase_key_src, 128);
	loop(16)
	mbedtls_aes_crypt_ecb(aes_dec, MBEDTLS_AES_DECRYPT, enc+index*16, dec+index*16);
	dbg_print("mbedtls AES ECB decode time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	// 显示
	//dbg_u8_print("src: \n", src, 256, 32);
	dbg_u8_print("enc: \n", enc, 256, 32);
	dbg_u8_print("dec: \n", dec, 256, 32);
	
	dbg_puts(SYMBOL_LINE_ADD PTCR);
    /* AES 128 */
    /* Encrypt the plaintext message*/
	dat_buff_init();
	
	clk_start = bsp_cpu_clks_get();
    CRYP_Reset();
    CRYP_AES_ECB(CRYP_MODE_ENCRYPT, (uu8*)ase_key_src, 128, src, 256, enc);
	dbg_print("APM32 AES ECB encode time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));

	clk_start = bsp_cpu_clks_get();
    CRYP_Reset();
    CRYP_AES_ECB(CRYP_MODE_DECRYPT, (uu8*)ase_key_src, 128, enc, 256, dec);
	dbg_print("APM32 AES ECB decode time: %d us\n", bsp_clks_to_us(bsp_cpu_clks_get() - clk_start));
	
	// 显示
	//dbg_u8_print("src: \n", src, 256, 32);
	dbg_u8_print("enc: \n", enc, 256, 32);
	dbg_u8_print("dec: \n", dec, 256, 32);
	
	
	// 释放，用于清除内存中的密匙，属于安全性代码
	mbedtls_aes_free(aes_enc);
	mbedtls_aes_free(aes_dec);

	// 释放内存
	free(src);
	free(enc);
	free(dec);
	free(aes_enc);
	free(aes_dec);
}

/*******************************************************************************
 * @brief: aes_ecb_cal
 * @param argc 参数数量
 * @param argv 参数指针
 * @return 错误代码
 ******************************************************************************/
int aes_ecb_cal(int argc, char *argv[])
{
	aes_ecb_demo();
	
	return 0;
}
DBG_FUN_EXPORT(aes_ecb_cal);

/*******************************************************************************
 * @brief: aes_cbc_cal
 * @param argc 参数数量
 * @param argv 参数指针
 * @return 错误代码
 ******************************************************************************/
int aes_cbc_cal(int argc, char *argv[])
{
	aes_cbc_demo();
	
	return 0;
}
DBG_FUN_EXPORT(aes_cbc_cal);
